from wormbane.Feature import Floor
from wormbane.generate_level import generate_level
from wormbane.Item import Boulder
from wormbane.language import format_message
from wormbane.Level import Level
from wormbane.Monster import Elf, Monster
from wormbane.move import MoveError, move_item, move_monster
from wormbane.save import load_level, save_level
import random


def random_floor_tile(level):
    while True:
        room = random.choice(level.rooms)
        x = random.randrange(room.bounds.min.x + 1, room.bounds.max.x - 1)
        y = random.randrange(room.bounds.min.y + 1, room.bounds.max.y - 1)
        tile = level.tiles[x][y]
        if type(tile.feature) is Floor and tile.passable:
            return tile


class Game(object):

    def __init__(self):

        # initialize state
        self.messages = []
        self.current_level = generate_level()
        self.level_nums = set([self.current_level.num])
        self.completed = False
        self.depth = 7

        # create hero
        self.hero = Elf()
        self.hero.protection = 10.0
        move_monster(self, self.hero, self.current_level.stair_up_tile)
        self.current_level.push_monster(self.hero)

        self.generate_monsters()
        self.generate_boulders()

    def generate_monsters(self, count=1):
        max_exp_level = max(self.hero.exp_level, self.current_level.num)
        classes = [cls for cls in Monster.__subclasses__()
                   if not cls.is_nemesis
                   and cls.min_exp_level <= max_exp_level]
        for i in xrange(count):
            tile = random_floor_tile(self.current_level)
            cls = random.choice(classes)
            exp_level = random.randrange(cls.min_exp_level,
                                         min(max_exp_level,
                                             cls.max_exp_level) + 1)
            monster = cls(exp_level=exp_level)
            move_monster(self, monster, tile)
            self.current_level.push_monster(monster)

    def generate_nemesis(self):
        classes = [cls for cls in Monster.__subclasses__()
                   if cls.is_nemesis]
        tile = random_floor_tile(self.current_level)
        nemesis = random.choice(classes)()
        move_monster(self, nemesis, tile)
        self.current_level.push_monster(nemesis)

    def generate_boulders(self):
        for i in xrange(random.randrange(1, 4)):
            tile = random_floor_tile(self.current_level)
            if tile.passable:
                move_item(self, Boulder(), tile)

    def change_level(self, num):
        dir = 'down' if num > self.current_level.num else 'up'
        move_monster(self, self.hero, None)
        save_level(self.current_level)
        if num in self.level_nums:
            self.current_level = load_level(num)
        else:
            self.current_level = generate_level()
            self.current_level.num = num
            self.level_nums.add(num)
            if num == self.depth:
                self.current_level.stair_down_tile.feature = Floor()
                self.current_level.stair_down_tile = None
                self.generate_nemesis()
                self.generate_monsters(num - 1)
            else:
                self.generate_monsters(num)
            self.generate_boulders()
        self.hero.time = self.current_level.time
        move_monster(self, self.hero,
                     self.current_level.stair_up_tile if dir == 'down'
                     else self.current_level.stair_down_tile)

    def write(self, *args):
        if len(args) == 1:
            # Plain message.
            message = args[0]
        else:
            message = format_message(observer=self.hero, *args)
        self.messages.append(message)
